﻿//---------------------------------------------------------------------
// <copyright file="ODataPayloadJsonConverter.cs" company="Microsoft">
//      Copyright (C) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
// </copyright>
//---------------------------------------------------------------------

namespace Microsoft.Test.Taupo.OData.Common
{
    using System;
    using System.Xml;
    using Microsoft.Test.Taupo.Astoria.Common;
    using Microsoft.Test.Taupo.Astoria.Contracts;
    using Microsoft.Test.Taupo.Astoria.Contracts.OData;
    using Microsoft.Test.Taupo.Astoria.OData;
    using Microsoft.Test.Taupo.Common;

    /// <summary>
    /// Visitor to convert primitive values and remove annotations
    /// </summary>
    public class ODataPayloadJsonConverter : ODataPayloadElementVisitorBase, IODataPayloadElementVisitor
    {
        private readonly DataServiceProtocolVersion protocolVersion;
        
        /// <summary>
        /// Creates or initializes a new instance of ODataPayloadJsonConverter type
        /// </summary>
        /// <param name="protocolVersion">The version to use</param>
        public ODataPayloadJsonConverter(DataServiceProtocolVersion protocolVersion)
        {
            ExceptionUtilities.Assert(protocolVersion != DataServiceProtocolVersion.Unspecified, "Protocol version must be specified");
            this.protocolVersion = protocolVersion;
        }

        /// <summary>
        /// Convert clr values to JSON primitive representations for primitiveValue payloadElement so that when this can be
        /// compared against the one generated by the JSON DeSerializer
        /// </summary>
        /// <param name="payloadElement">payloadElement to convert primitive values from</param>
        public override void Visit(PrimitiveValue payloadElement)
        {
            // convert byte array to string rep for JSON according to OData rules
            byte[] bytes = payloadElement.ClrValue as byte[];
            if (bytes != null)
            {
                payloadElement.ClrValue = Convert.ToBase64String(bytes);
                return;
            }

            // convert int to long since the DeSerializer we use converts JSON numbers to longs
            int? num = payloadElement.ClrValue as int?;
            if (num != null)
            {
                payloadElement.ClrValue = Convert.ToInt64(num);
                return;
            }

            // int64 and decimals are represented as JSON strings , so do the same for help with later comparison
            if (payloadElement.ClrValue is Int64 || payloadElement.ClrValue is decimal)
            {
                payloadElement.ClrValue = payloadElement.ClrValue.ToString();
                return;
            }

            // convert TimeSpans to JSON data representation
            TimeSpan? timespan = payloadElement.ClrValue as TimeSpan?;
            if (timespan != null)
            {
                payloadElement.ClrValue = XmlConvert.ToString(timespan.Value);
            }

            // Convert DateTimeOffsets to JSON Data representation
            DateTimeOffset? dto = payloadElement.ClrValue as DateTimeOffset?;
            if (dto != null)
            {
                payloadElement.ClrValue = XmlConvert.ToString(dto.Value);
            }

            // Convert DateTimes to JSON Data representation
            DateTime? date = payloadElement.ClrValue as DateTime?;
            if (date != null)
            {
                payloadElement.ClrValue = XmlConvert.ToString(date.Value, XmlDateTimeSerializationMode.RoundtripKind);
            }
        }

        /// <summary>
        /// Visit the EntityInstance to remove annotations.
        /// </summary>
        /// <param name="payloadElement"> payloadElement to visit</param>
        public override void Visit(EntityInstance payloadElement)
        {
            payloadElement.Annotations.Clear();
            base.Visit(payloadElement);
        }

        /// <summary>
        /// Visit the EntitySetInstance to remove annotations.
        /// </summary>
        /// <param name="payloadElement">payloadElement to visit</param>
        public override void Visit(EntitySetInstance payloadElement)
        {
            payloadElement.Annotations.Clear();
            base.Visit(payloadElement);
        }
    }
}
